﻿using AssemblyVerifier;
using DynamicProxies;
using DynamicProxies.Tests.InterfaceImplementation;
using DynamicProxies.Tests.Types;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Reflection;
using System.Reflection.Emit;

namespace DynamicProxies.Tests
{
	[TestClass]
	public sealed class ReferenceArgumentTypeTests : BaseTests
	{
		private bool changeBefore;
		private bool changeAfter;

		[TestMethod]
		public void CallMethodWithByRefReferenceArgumentAndNoChanges()
		{
			this.changeBefore = false;
			this.changeAfter = false;

			var proxy = Proxy.Create<DifferentArgumentCombinations>(this);

			var value = "Not Changed";
			proxy.HookWithByRefArgument(ref value);

			Assert.AreEqual("Not Changed", value);
		}

		[TestMethod]
		public void CallMethodWithByRefReferenceArgumentAndChangeValueAfter()
		{
			this.changeBefore = false;
			this.changeAfter = true;
			
			var proxy = Proxy.Create<DifferentArgumentCombinations>(this);

			var value = "Not Changed";
			proxy.HookWithByRefArgument(ref value);

			Assert.AreEqual("Changed", value);
		}

		[TestMethod]
		public void CallMethodWithByRefReferenceArgumentAndChangeValueBefore()
		{
			this.changeBefore = true;
			this.changeAfter = false;
			
			var proxy = Proxy.Create<DifferentArgumentCombinations>(this);
			
			var value = "Not Changed";
			proxy.HookWithByRefArgument(ref value);
			
			Assert.AreEqual("Changed", value);
		}

		protected override bool OnAfterMethodInvocation(MethodBase target, object[] arguments, ref object returnValue, Exception generatedException)
		{
			if(target.Name == "HookWithByRefArgument" && this.changeAfter)
			{
				arguments[0] = "Changed";
			}

			return false;
		}
		
		protected override bool OnBeforeMethodInvocation(MethodBase target, object[] arguments)
		{
			if(target.Name == "HookWithByRefArgument" && this.changeBefore)
			{
				arguments[0] = "Changed";
			}
			
			return true;
		}
	}
}
